/*!
 * glDatePicker v2.0
 * http://glad.github.com/glDatePicker/
 *
 * Copyright (c) 2013 Gautam Lad.  All rights reserved.
 * Released under the MIT license.
 *
 * Date: Tue Jan 1 2013
 */
;
(function () {
    $.fn.glDatePicker = function (options) {
        var pluginName = 'glDatePicker';

        // Find the plugin attached to the element
        var instance = this.data(pluginName);

        // If the instance wasn't found, create it...
        if (!instance) {
            // Return the element being bound to
            return this.each(function () {
                return $(this).data(pluginName, new glDatePicker(this, options));
            });
        }

        // ...otherwise if the user passes true to the plugin (on the second call),
        // then return the instance of the plugin itself
        return (options === true) ? instance : this;
    };

    // Default options
    $.fn.glDatePicker.defaults =
    {
        // Style to use for the calendar.  This name must match the name used in
        // the stylesheet, using the class naming convention "gldp-cssName".
        cssName: 'default',

        // The z-index for the calendar control.
        zIndex: 1000,

        // Thickness of border (in pixels)
        borderSize: 1,

        // The number of pixels to offset the calendar's position on the page.
        calendarOffset: {x: 0, y: 1},

        // Set to true if you want the calendar to be visible at all times.
        // NOTE: If your target element is hidden, the calendar will be hidden as well.
        showAlways: false,

        // Hide the calendar when a date is selected (only if showAlways is set to false).
        hideOnClick: true,

        // Allow selection of months by clicking on the month in the title.
        allowMonthSelect: true,

        // Allow selection of years by clicking on the year in the title.
        allowYearSelect: true,

        // The date that will be treated as 'today'.
        todayDate: new Date(),

        // The date that will appear selected when the calendar renders.
        // By default it will be set to todayDate.
        selectedDate: null,

        // Arrows used for the Previous and Next month buttons on the title.
        // Set these to blank to hide the arrows completely.
        prevArrow: '\u25c4',
        nextArrow: '\u25ba',

        // A collection of dates that can be selectable by the user.
        // The dates can be a one-time selection or made repeatable by setting
        // the repeatYear or repeatMonth flag to true.
        // By default repeatYear and repeatMonth are false.
        //
        // This example creates 4-individual dates that can be selected;
        // The first date will repeat every year, the second date will repeat every
        // month and year, the third date will repeat every month and the fourth date
        // will only be selectable one-time and not repeat:
        //
        //    selectableDates: [
        //        { date: new Date(0, 8, 5), repeatYear: true },
        //        { date: new Date(0, 0, 14), repeatMonth: true, repeatYear: true },
        //        { date: new Date(2013, 0, 24), repeatMonth: true },
        //        { date: new Date(2013, 11, 25) },
        //    ]
        selectableDates: null,

        // A collection of date ranges that are selectable by the user.
        // The ranges can be made to repeat by setting repeatYear to true
        // (repeatMonth is not supported).
        //
        // This example will create 3-sets of selectable date ranges with
        // specific from and to ranges.  The 4th and 5th ranges don't specify
        // the "to" date in which case the "to" date will be the maximum days for
        // the month specified in "from".  The 4th and 5th ranges also repeat every year:
        //
        //     selectableDateRange: [
        //         { from: new Date(2013, 1, 1), to: newDate (2013, 2, 1) },
        //         { from: new Date(2013, 4, 1), to: newDate (2013, 8, 1) },
        //         { from: new Date(2013, 7, 10), to: newDate (2013, 9, 10) },
        //         { from: new Date(0, 8, 10), repeatYear: true }
        //         { from: new Date(0, 9, 1), repeatYear: true }
        //     ]
        selectableDateRange: null,

        // Mark certain dates as special dates.  Similar to selectableDates, this
        // property supports both repeatYear and repeatMonth flags.
        // Each special date can be styled using custom style names and can have
        // data attached to it that will be returned in the onClick callback.
        // The data field can be any custom (JSON style) object.
        //
        // This example creates two (repeatable by year) dates with special data in them.
        // The first date also assigns a special class (which you will have to define).
        //    specialDates: [
        //        {
        //            date: new Date(0, 8, 5),
        //            data: { message: 'Happy Birthday!' },
        //            repeatYear: true,
        //            cssClass: 'special-bday'
        //        },
        //        {
        //            date: new Date(2013, 0, 8),
        //            data: { message: 'Meeting every day 8 of the month' },
        //            repeatMonth: true
        //        }
        //    ]
        specialDates: null,

        // List of months that can be selectable, including when the user clicks
        // on the title to select from the dropdown.
        // This example only makes two months visible; September and December:
        //    selectableMonths: [8, 11]
        selectableMonths: null,

        // List of selectable years.  If not provided, will default to 5-years
        // back and forward.
        // This example only allows selection of dates that have year 2012, 2013, 2015
        //    selectableYears: [2012, 2013, 2015]
        selectableYears: null,

        // List of selectable days of the week.  0 is Sunday, 1 is Monday, and so on.
        // This example allows only Sunday, Tuesday, Thursday:
        //    selectableDOW: [0, 2, 4]
        selectableDOW: null,

        // Names of the month that will be shown in the title.
        // Will default to long-form names:
        //     January, February, March, April, May, June, July,
        //     August, September, October, November, December
        monthNames: null,

        // Names of the days of the Week that will be shown below the title.
        // Will default to short-form names:
        //     Sun, Mon, Tue, Wed, Thu, Fri, Sat
        dowNames: null,

        // The day of the week to start the calendar on.  0 is Sunday, 1 is Monday and so on.
        dowOffset: 0,

        // Callback that will trigger when the user clicks a selectable date.
        // Parameters that are passed to the callback:
        //     el : The input element the date picker is bound to
        //   cell : The cell on the calendar that triggered this event
        //   date : The date associated with the cell
        //   data : Special data associated with the cell (if available, otherwise, null)
        onClick: (function (el, cell, date, data) {
            el.val(date.toLocaleDateString());
        }),

        // Callback that will trigger when the user hovers over a selectable date.
        // This callback receives the same set of parameters as onClick.
        onHover: function (el, cell, date, data) {
        },

        // Callback that will trigger when the calendar needs to show.
        // You can use this callback to animate the opening of the calendar.
        onShow: function (calendar) {
            calendar.show();
        },

        // Callback that will trigger when the calendar needs to hide.
        // You can use this callback to animate the hiding of the calendar.
        onHide: function (calendar) {
            calendar.hide();
        },

        // First date of the month.
        firstDate: null
    };

    // Our plugin object
    var glDatePicker = (function () {
        // Main entry point.  Initialize the plugin
        function glDatePicker(element, userOptions) {
            // Grab handle to this
            var self = this;

            // Save bound element to el
            self.el = $(element);
            var el = self.el;

            // Merge user options into default options
            self.options = $.extend(true, {}, $.fn.glDatePicker.defaults, userOptions);
            var options = self.options;

            // Find the calendar element if the user provided one
            self.calendar = $($.find('[gldp-el=' + el.attr('gldp-id') + ' ]'));

            // Default first date to selected
            options.selectedDate = options.selectedDate || options.todayDate;
            options.firstDate = (new Date((options.firstDate || options.selectedDate)))._first();

            if (!(el.attr('gldp-id') || '').length) {
                el.attr('gldp-id', 'gldp-' + Math.round(Math.random() * 1e10))
            }

            // Show the plugin on focus
            el
                .addClass('gldp-el')
                .bind('click', function (e) {
                    self.show(e);
                })
                .bind('focus', function (e) {
                    self.show(e);
                });

            // If the user is defining the container and it exists, hide it on initial creation.
            // The update function will handle showing if it's showAlways = true
            if (self.calendar.length && !options.showAlways) {
                self.calendar.hide();
            }

            // Hide the plugin on mouse up outside of the plugin
            $(document).bind('mouseup', function (e) {
                var target = e.target;
                var calendar = self.calendar;

                if (!el.is(target) && !calendar.is(target) && calendar.has(target).length === 0 && calendar.is(':visible')) {
                    self.hide();
                }
            });

            // Render calendar
            self.render();
        };

        // Public methods
        glDatePicker.prototype =
        {
            show: function () {
                // Hide others and show this calendar
                $.each($('.gldp-el').not(this.el), function (i, o) {
                    if (o.length) {
                        o.options.onHide(o.calendar);
                    }
                });

                // Show this calendar
                this.options.onShow(this.calendar);
            },

            hide: function () {
                if (this.options && !this.options.showAlways) {
                    this.options.onHide(this.calendar);
                }
            },

            // Render the calendar
            render: function (renderCalback) {
                var self = this;
                var el = self.el;
                var options = self.options;
                var calendar = self.calendar;

                // Build a core class (with border) that every element would have
                var coreClass = ' core border ';
                var cssName = 'gldp-' + options.cssName;

                // Get today
                var todayVal = options.todayDate._val();
                var todayTime = todayVal.time;

                // Constants
                var maxRow = 6;
                var maxCol = 7;
                var borderSize = options.borderSize + 'px';

                // Helper function to build selectable list
                var getSelectableList = function (min, max, userList) {
                    // Build a default list using min/max
                    var resultList = [];
                    for (var i = min; i <= max; i++) {
                        resultList.push(i);
                    }

                    // If user provided a collection, sanitize list by ensuring it's within range and unique
                    if (userList) {
                        var newList = [];
                        $.each(userList, function (i, v) {
                            if (v >= min && v <= max && newList._indexOf(v) < 0) {
                                newList.push(v);
                            }
                        });

                        resultList = newList.length ? newList : resultList;
                    }
                    ;

                    // Sort the values before returning it
                    resultList.sort();

                    return resultList;
                };

                // Selectable (constants)
                var selectableMonths = getSelectableList(0, 11, options.selectableMonths);
                var selectableYears = getSelectableList(todayVal.year - 5, todayVal.year + 5, options.selectableYears);
                var selectableDOW = getSelectableList(0, 6, options.selectableDOW);
                var dowNames = options.dowNames || ['日', '一', '二', '三', '四', '五', '六'];
                var monthNames = options.monthNames || ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];

                // Create cell width based on el size
                var containerWidth = el.outerWidth();
                var containerHeight = containerWidth;

                // Create cell size based on container size
                var getCellSize = function (_size, _count) {
                    return (_size / _count) + ((options.borderSize / _count) * (_count - 1));
                };
                var cellWidth = getCellSize(containerWidth, maxCol);
                var cellHeight = getCellSize(containerHeight, maxRow + 2);

                // If calendar doesn't exist, create it and re-assign it to self
                if (!calendar.length) {
                    self.calendar = calendar = $('<div/>')
                        .attr('gldp-el', el.attr('gldp-id'))
                        .data('is', true)
                        .css(
                        {
                            display: (options.showAlways ? undefined : 'none'),
                            zIndex: options.zIndex,
                            width: (cellWidth * maxCol) + 'px'
                        });

                    $('body').append(calendar);
                }
                else {
                    if (!eval(calendar.data('is'))) {
                        containerWidth = calendar.outerWidth();
                        containerHeight = calendar.outerHeight();

                        cellWidth = getCellSize(containerWidth, maxCol);
                        cellHeight = getCellSize(containerHeight, maxRow + 2);
                    }
                }

                // Hide calendar if the target element isn't visible
                if (!el.is(':visible')) {
                    calendar.hide();
                }

                // Add core classes and remove calendar's children
                calendar
                    .removeClass()
                    .addClass(cssName)
                    .children().remove();

                // Bind to resize event to position calendar
                var onResize = function () {
                    var elPos = el.offset();
                    calendar.css(
                        {
                            top: (elPos.top + el.outerHeight() + options.calendarOffset.y) + 'px',
                            left: (elPos.left + options.calendarOffset.x) + 'px'
                        });
                };
                $(window).resize(onResize);
                onResize();

                // Create variables for cells
                var cellCSS =
                {
                    width: cellWidth + 'px',
                    height: cellHeight + 'px',
                    lineHeight: cellHeight + 'px'
                };

                // Helper function to setDate
                var setFirstDate = function (_date) {
                    if (_date) {
                        // Get first date
                        options.firstDate = _date;

                        // Update the calendar
                        self.render();
                    }
                };

                var getFirstDate = function (_offset) {
                    // Create start date as the first date of the month
                    var _date = new Date(options.firstDate);

                    // Default to no offset
                    _offset = _offset || 0;

                    // Find out which months are selectable
                    while (true) {
                        // Adjust date for month offset
                        _date.setMonth(_date.getMonth() + _offset);
                        _date.setDate(Math.min(1, _date._max()));

                        // If not an offset, break out of the loop
                        if (_offset == 0) {
                            break;
                        }

                        // Get _date's value
                        var dateVal = _date._val();

                        // Get local vars
                        var dateMonth = dateVal.month;
                        var dateYear = dateVal.year;

                        // Find the month first
                        if (selectableMonths._indexOf(dateMonth) != -1) {
                            // If year is in our collection, break...
                            if (selectableYears._indexOf(dateYear) != -1) {
                                break;
                            }
                            else {
                                // ...otherwise, if it's out of bounds, exit loop
                                if (dateYear < selectableYears[0] || dateYear > selectableYears[selectableYears.length - 1]) {
                                    return null;
                                }
                            }
                        }
                    }

                    return _date;
                };

                // Get the previous, next first dates
                var prevFirstDate = getFirstDate(-1);
                var nextFirstDate = getFirstDate(1);

                // Get the first date for the current month being rendered
                var firstDate = (options.firstDate = getFirstDate());
                var firstDateVal = firstDate._val();
                var firstDateMonth = firstDateVal.month;
                var firstDateYear = firstDateVal.year;

                // Get the start date in the calendar
                var startDate = new Date(firstDate);

                // Sanitize days of the week offset
                var dowOffset = Math.abs(Math.min(6, Math.max(0, options.dowOffset)));

                // Offset weekdays
                var startOffset = startDate.getDay() - dowOffset;
                startOffset = startOffset < 1 ? -7 - startOffset : -startOffset;
                dowNames = (dowNames.concat(dowNames))
                    .slice(dowOffset, dowOffset + 7);

                // Offset the start date
                startDate._add(startOffset);

                // Gather flags for prev/next arrows
                var showPrev = (prevFirstDate);
                var showNext = (nextFirstDate);

                // Create the arrows and title
                var monyearClass = coreClass + 'monyear ';

                var prevCell = $('<div/>')
                    .addClass(monyearClass)
                    .css(
                    $.extend({}, cellCSS,
                        {
                            borderWidth: borderSize + ' 0 0 ' + borderSize
                        })
                )
                    .append(
                    $('<a/>')
                        .addClass('prev-arrow' + (showPrev ? '' : '-off'))
                        .html(options.prevArrow)
                )
                    .mousedown(function () {
                        return false;
                    })
                    .click(function (e) {
                        if (options.prevArrow != '' && showPrev) {
                            e.stopPropagation();
                            setFirstDate(prevFirstDate);
                        }
                    });

                var titleCellCount = maxCol - 2;
                var titleWidth = (cellWidth * titleCellCount) - (titleCellCount * options.borderSize) + (options.borderSize);
                var titleCell = $('<div/>')
                    .addClass(monyearClass + 'title')
                    .css(
                    $.extend({}, cellCSS,
                        {
                            width: titleWidth + 'px',
                            borderTopWidth: borderSize,
                            marginLeft: '-' + (borderSize)
                        })
                );

                var nextCell = $('<div/>')
                    .addClass(monyearClass)
                    .css(
                    $.extend({}, cellCSS,
                        {
                            marginLeft: '-' + (borderSize),
                            borderWidth: borderSize + ' ' + borderSize + ' 0 0'
                        })
                )
                    .append(
                    $('<a/>')
                        .addClass('next-arrow' + (showNext ? '' : '-off'))
                        .html(options.nextArrow)
                )
                    .mousedown(function () {
                        return false;
                    })
                    .click(function (e) {
                        if (options.nextArrow != '' && showNext) {
                            e.stopPropagation();
                            setFirstDate(nextFirstDate);
                        }
                    });

                // Add cells for prev/title/next
                calendar
                    .append(prevCell)
                    .append(titleCell)
                    .append(nextCell);

                // Add all the cells to the calendar
                for (var row = 0, cellIndex = 0; row < maxRow + 1; row++) {
                    for (var col = 0; col < maxCol; col++, cellIndex++) {
                        var cellDate = new Date(startDate);
                        var cellClass = 'day';
                        var cellZIndex = options.zIndex + (cellIndex);
                        var cell = $('<div/>')

                        if (!row) {
                            cellClass = 'dow';
                            cell.html(dowNames[col]);
                            cellDate = null;
                        }
                        else {
                            // Get the new date for this cell
                            cellDate._add(col + ((row - 1) * maxCol));

                            // Get value for this date
                            var cellDateVal = cellDate._val();
                            var cellDateTime = cellDateVal.time;

                            // Variable to hold special data
                            var specialData = null;

                            // Determine if this date is selectable
                            var isSelectable = true;

                            // Helper function to get repeat friendly date against current date
                            var getRepeatDate = function (v, date) {
                                // If repeating, set the date's year and month accordingly
                                if (v.repeatYear === true) {
                                    date.setYear(cellDateVal.year);
                                }
                                if (v.repeatMonth === true) {
                                    date.setMonth(cellDateVal.month);
                                }

                                return date._val();
                            };

                            // Assign date for the cell
                            cell.html(cellDateVal.date);

                            // If we have selectable date ranges
                            if (options.selectableDateRange) {
                                isSelectable = false;
                                $.each(options.selectableDateRange, function (i, v) {
                                    var dateFrom = v.from;
                                    var dateTo = (v.to || null);

                                    // If to is not specified, default to max days in the from month
                                    dateTo = dateTo || new Date(v.from.getFullYear(), v.from.getMonth(), v.from._max());

                                    // If repeating year, set the from and two to the current date's year
                                    dateFrom = getRepeatDate(v, dateFrom);
                                    dateTo = getRepeatDate(v, dateTo);

                                    // Test to see if this date is selectable
                                    if (cellDateTime >= dateFrom.time && cellDateTime <= dateTo.time) {
                                        isSelectable = true;
                                        return true;
                                    }
                                });
                            }

                            // Handle date ranges and collections
                            if (options.selectableDates) {
                                if ((options.selectableDateRange && !isSelectable) || (isSelectable && !options.selectableDateRange)) {
                                    isSelectable = false;
                                }
                                $.each(options.selectableDates, function (i, v) {
                                    var vDate = getRepeatDate(v, v.date);

                                    if (vDate.time == cellDateTime) {
                                        return (isSelectable = true);
                                    }
                                });
                            }

                            // If not active or if not within selectableMonths, set to noday otherwise evaluate accordingly
                            if (!isSelectable ||
                                selectableYears._indexOf(cellDateVal.year) < 0 ||
                                selectableMonths._indexOf(cellDateVal.month) < 0 ||
                                selectableDOW._indexOf(cellDateVal.day) < 0) {
                                cellClass = 'noday';
                            }
                            else {
                                // Handle active dates and weekends
                                cellClass = (['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'])[cellDateVal.day];

                                // Handle today or selected dates
                                if (firstDateMonth != cellDateVal.month) {
                                    cellClass += ' outday';
                                }
                                if (todayTime == cellDateTime) {
                                    cellClass = 'today';
                                    cellZIndex += 50;
                                }
                                if (options.selectedDate._time() == cellDateTime) {
                                    cellClass = 'selected';
                                    cellZIndex += 51;
                                }

                                // Handle special dates
                                if (options.specialDates) {
                                    $.each(options.specialDates, function (i, v) {
                                        var vDate = getRepeatDate(v, v.date);

                                        if (vDate.time == cellDateTime) {
                                            cellClass = (v.cssClass || 'special');
                                            cellZIndex += 52;
                                            specialData = v.data;
                                        }
                                    });
                                }

                                cell
                                    .mousedown(function () {
                                        return false;
                                    })
                                    .hover(function (e) {
                                        e.stopPropagation();

                                        // Get the data from this cell
                                        var hoverData = $(this).data('data');

                                        // Call callback
                                        options.onHover(el, cell, hoverData.date, hoverData.data);
                                    })
                                    .click(function (e) {
                                        e.stopPropagation();

                                        // Get the data from this cell
                                        var clickedData = $(this).data('data');

                                        // Save date to selected and first
                                        options.selectedDate = options.firstDate = clickedData.date;

                                        // Update calendar (and auto-hide if necessary)
                                        self.render(function () {
                                            if (!options.showAlways && options.hideOnClick) {
                                                self.hide();
                                            }
                                        });

                                        // Call callback
                                        options.onClick(el, $(this), clickedData.date, clickedData.data);
                                    });
                            }
                        }

                        // Update the css for the cell
                        $.extend(cellCSS,
                            {
                                borderTopWidth: borderSize,
                                borderBottomWidth: borderSize,
                                borderLeftWidth: (row > 0 || (!row && !col)) ? borderSize : 0,
                                borderRightWidth: (row > 0 || (!row && col == 6)) ? borderSize : 0,
                                marginLeft: (col > 0) ? '-' + (borderSize) : 0,
                                marginTop: (row > 0) ? '-' + (borderSize) : 0,
                                zIndex: cellZIndex
                            });

                        // Assign other properties to the cell
                        cell
                            .data('data', {date: cellDate, data: specialData})
                            .addClass(coreClass + cellClass)
                            .css(cellCSS);

                        // Add cell to calendar
                        calendar.append(cell);
                    }
                }

                // Render the month / year title

                // Helper function for toggling select and text
                var toggleYearMonthSelect = function (showYear) {
                    var show = 'inline-block';
                    var hide = 'none';

                    if (options.allowMonthSelect) {
                        monthText.css({display: !showYear ? hide : show});
                        monthSelect.css({display: !showYear ? show : hide});
                    }

                    if (options.allowYearSelect) {
                        yearText.css({display: showYear ? hide : show});
                        yearSelect.css({display: showYear ? show : hide});
                    }
                };

                // Helper function when select is updated
                var onYearMonthSelect = function () {
                    options.firstDate = new Date(yearSelect.val(), monthSelect.val(), 1);
                    self.render();
                };

                // Build month selector
                var monthSelect = $('<select/>')
                    .hide()
                    .change(onYearMonthSelect);

                // Build year selector
                var yearSelect = $('<select/>')
                    .hide()
                    .change(onYearMonthSelect);

                // Build month label
                var monthText = $('<span/>')
                    .html(monthNames[firstDateMonth])
                    .mousedown(function () {
                        return false;
                    })
                    .click(function (e) {
                        e.stopPropagation();
                        toggleYearMonthSelect(false);
                    });

                // Build year label
                var yearText = $('<span/>')
                    .html(firstDateYear)
                    .mousedown(function () {
                        return false;
                    })
                    .click(function (e) {
                        e.stopPropagation();
                        toggleYearMonthSelect(true);
                    });

                // Populate month select
                $.each(monthNames, function (i, v) {
                    if (options.allowMonthSelect && selectableMonths._indexOf(i) != -1) {
                        var o = $('<option/>').html(v).attr('value', i);
                        if (i == firstDateMonth) {
                            o.attr('selected', 'selected');
                        }
                        monthSelect.append(o);
                    }
                });

                // Populate year select
                $.each(selectableYears, function (i, v) {
                    if (options.allowYearSelect) {
                        var o = $('<option/>').html(v).attr('value', v);
                        if (v == firstDateYear) {
                            o.attr('selected', 'selected');
                        }
                        yearSelect.append(o);
                    }
                });

                var titleYearMonth = $('<div/>')
                    .append(monthText)
                    .append(monthSelect)
                    .append(yearText)
                    .append(yearSelect);

                // Add to title
                titleCell.children().remove();
                titleCell.append(titleYearMonth);

                // Run the callback signaling end of the render
                renderCalback = renderCalback || (function () {
                });
                renderCalback();
            }
        };

        // Return the plugin
        return glDatePicker;
    })();

    // One time initialization of useful prototypes
    (function () {
        Date.prototype._clear = function () {
            this.setHours(0);
            this.setMinutes(0);
            this.setSeconds(0);
            this.setMilliseconds(0);

            return this;
        };

        Date.prototype._time = function () {
            return this._clear().getTime();
        };

        Date.prototype._max = function () {
            var isLeapYear = (new Date(this.getYear(), 1, 29).getMonth() == 1) ? 1 : 0;
            var days = [31, 28 + isLeapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

            return days[this.getMonth()];
        };

        Date.prototype._add = function (days) {
            this.setDate(this.getDate() + days);
        };

        Date.prototype._first = function () {
            var date = new Date(this);
            date.setDate(1);

            return date;
        };

        Date.prototype._val = function () {
            this._clear();

            return {
                year: this.getFullYear(),
                month: this.getMonth(),
                date: this.getDate(),
                time: this.getTime(),
                day: this.getDay()
            };
        };

        Array.prototype._indexOf = function (value) {
            return $.inArray(value, this);
        }
    })();
})();
